import { getMySQLPool } from '../database/mysql';
import { utils } from './utils';
import { Log } from '../database/models';

/**
 * 日志类型
 */
export enum LogType {
  API = 'api',
  KOA = 'koa',
  MYSQL = 'mysql',
  REDIS = 'redis',
  ERROR = 'error',
  OTHER = 'other',
}

/**
 * 日志级别
 */
export enum LogLevel {
  DEBUG = 'debug',
  INFO = 'info',
  WARN = 'warn',
  ERROR = 'error',
}

/**
 * ANSI 颜色代码
 */
const colors = {
  reset: '\x1b[0m',
  dim: '\x1b[2m',
  bright: '\x1b[1m',
  red: '\x1b[31m',
  green: '\x1b[32m',
  yellow: '\x1b[33m',
  blue: '\x1b[34m',
  cyan: '\x1b[36m',
  white: '\x1b[37m',
};

/**
 * 获取日志级别的颜色
 */
function getLevelColor(level: LogLevel): string {
  switch (level) {
    case LogLevel.DEBUG:
      return colors.cyan;
    case LogLevel.INFO:
      return colors.green;
    case LogLevel.WARN:
      return colors.yellow;
    case LogLevel.ERROR:
      return colors.red;
    default:
      return colors.white;
  }
}

/**
 * 获取日志类型的显示名称
 */
function getTypeDisplayName(type: LogType): string {
  const names: Record<LogType, string> = {
    [LogType.API]: 'API',
    [LogType.KOA]: 'KOA',
    [LogType.MYSQL]: 'MYSQL',
    [LogType.REDIS]: 'REDIS',
    [LogType.ERROR]: 'ERROR',
    [LogType.OTHER]: 'OTHER',
  };
  return names[type] || 'OTHER';
}

/**
 * 格式化时间戳
 */
function formatTimestamp(): string {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');
  return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

/**
 * 统一的控制台日志打印函数
 * 将日志类型、级别、消息等信息融合成一条格式化的输出
 */
export function consoleLog(
  type: LogType,
  level: LogLevel,
  message: string,
  extra?: {
    requestId?: string;
    userId?: string;
    method?: string;
    url?: string;
    ip?: string;
    error?: any;
    [key: string]: any;
  }
): void {
  const timestamp = formatTimestamp();
  const levelColor = getLevelColor(level);
  const typeName = getTypeDisplayName(type);
  const levelName = level.toUpperCase().padEnd(5);
  
  // 构建基础日志信息
  let logLine = `${colors.dim}[${timestamp}]${colors.reset} `;
  logLine += `${colors.dim}[${typeName}]${colors.reset} `;
  logLine += `${levelColor}${levelName}${colors.reset} `;
  logLine += message;
  
  // 添加额外信息
  const extraParts: string[] = [];
  if (extra?.requestId) {
    extraParts.push(`requestId=${extra.requestId}`);
  }
  if (extra?.userId) {
    extraParts.push(`userId=${extra.userId}`);
  }
  if (extra?.method && extra?.url) {
    extraParts.push(`${extra.method} ${extra.url}`);
  }
  if (extra?.ip) {
    extraParts.push(`ip=${extra.ip}`);
  }
  if (extra?.error) {
    const errorMsg = extra.error?.message || String(extra.error);
    extraParts.push(`error=${errorMsg}`);
  }
  
  // 如果有额外信息，添加到日志行
  if (extraParts.length > 0) {
    logLine += ` ${colors.dim}(${extraParts.join(', ')})${colors.reset}`;
  }
  
  // 根据日志级别选择输出方法
  if (level === LogLevel.ERROR) {
    console.error(logLine);
    // 如果是错误且有堆栈信息，也打印堆栈
    if (extra?.error?.stack) {
      console.error(colors.dim + extra.error.stack + colors.reset);
    }
  } else if (level === LogLevel.WARN) {
    console.warn(logLine);
  } else {
    console.log(logLine);
  }
}

/**
 * 记录日志到数据库
 * 注意：此函数直接使用 MySQL 连接池，避免循环依赖
 */
export async function logToDatabase(
  requestId: string,
  type: LogType,
  level: LogLevel,
  message: string,
  data?: any,
  userId?: string,
  ip?: string,
  method?: string,
  url?: string
): Promise<void> {
  try {
    // 将 data 转换为 JSON 字符串，并限制长度（MEDIUMTEXT 最大 16MB，但为了安全限制为 10MB）
    let dataString: string | undefined = undefined;
    if (data) {
      try {
        dataString = JSON.stringify(data);
        // 限制 data 字段最大长度为 10MB（10 * 1024 * 1024 字节）
        // 如果超过，截断并添加提示
        const maxLength = 10 * 1024 * 1024; // 10MB
        if (dataString.length > maxLength) {
          dataString = dataString.substring(0, maxLength) + '...[数据已截断，原始长度: ' + dataString.length + ' 字节]';
        }
      } catch (e) {
        // JSON 序列化失败，尝试转换为字符串
        dataString = String(data);
        const maxLength = 10 * 1024 * 1024; // 10MB
        if (dataString.length > maxLength) {
          dataString = dataString.substring(0, maxLength) + '...[数据已截断，原始长度: ' + dataString.length + ' 字节]';
        }
      }
    }

    const log: Omit<Log, 'created_at'> = {
      id: utils.generateUUID(),
      request_id: requestId,
      user_id: userId,
      type,
      level,
      message,
      data: dataString,
      ip,
      method,
      url,
    };

    const sql = `
      INSERT INTO logs (id, request_id, user_id, type, level, message, data, ip, method, url)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    `;
    
    // 直接使用连接池执行，避免循环依赖
    const pool = getMySQLPool();
    await pool.execute(sql, [
      log.id,
      log.request_id,
      log.user_id || null,
      log.type,
      log.level,
      log.message,
      log.data || null,
      log.ip || null,
      log.method || null,
      log.url || null,
    ]);
  } catch (err) {
    // 日志记录失败不应该影响主流程，只打印到控制台
    // 避免在日志记录失败时再次记录日志，防止无限循环
    consoleLog(
      LogType.OTHER,
      LogLevel.ERROR,
      '日志记录失败',
      {
        error: err,
      }
    );
  }
}

